#include <gflags/gflags.h>

#include <cstdlib>
#include <iostream>
#include <memory>
#include <odb/database.hxx>
#include <odb/mysql/database.hxx>
#include <string>

#include "../../../common/log.h"
#include "student-odb.hxx"
#include "student.hxx"

DEFINE_string(ip, "127.0.0.1", "mysql服务器ip");
DEFINE_uint32(port, 0, "端口");
DEFINE_string(user, "root", "mysql用户");
DEFINE_string(password, "lwj225315", "对应用户的密码");
DEFINE_string(db, "odbTEST", "连接的mysql数据库");
DEFINE_string(charset, "utf8", "字符集");
DEFINE_int32(max_pool, 3, "Mysql连接池最大连接数量");
DEFINE_int32(level, 1, "日志等级");
DEFINE_bool(enable_debug, false, "调试模式");
DEFINE_string(path, "", "发布模式下, 日志输出到的文件路径");

bool insertClass(odb::mysql::database& db) {
    try {
        // 获取事务对象开启事务
        odb::transaction trans(db.begin());

        Classes c1 = Classes("高一一班");
        Classes c2 = Classes("高一二班");
        Classes c3 = Classes("高二一班");
        Classes c4 = Classes("高二二班");

        db.persist(c1);
        db.persist(c2);
        db.persist(c3);
        db.persist(c4);

        // 提交事务
        trans.commit();

    } catch (const std::exception& e) {
        LOG_ERROR("新增数据失败: {}", e.what());

        return false;
    }

    return true;
}

bool insertStudent(odb::mysql::database& db) {
    try {
        // 获取事务对象开启事务
        odb::transaction trans(db.begin());

        Student s1 = Student(1, "张三", 18, 1);
        Student s2 = Student(2, "李四", 20, 2);
        Student s3 = Student(3, "王五", 19, 3);
        Student s4 = Student(4, "赵六", 17, 2);
        Student s5 = Student(5, "田七", 21, 2);
        Student s6 = Student(6, "张八", 20, 1);

        db.persist(s1);
        db.persist(s2);
        db.persist(s3);
        db.persist(s4);
        db.persist(s5);
        db.persist(s6);

        // 提交事务
        trans.commit();

    } catch (const std::exception& e) {
        LOG_ERROR("新增数据失败: {}", e.what());

        return false;
    }

    return true;
}

Student selectStudent(odb::mysql::database& db) {
    Student res;

    try {
        // 获取事务对象开启事务
        odb::transaction trans(db.begin());

        odb::result<Student> r(
            db.query<Student>(odb::query<Student>::name == "张三"));
        if (r.size() != 1) {
            LOG_ERROR("查询到的数据量不对");
            return res;
        }

        res = *(r.begin());

        trans.commit();

    } catch (const std::exception& e) {
        LOG_ERROR("查找数据失败: {}", e.what());

        return res;
    }

    return res;
}

bool updateStudent(odb::mysql::database& db, const Student& stu) {
    try {
        // 获取事务对象开启事务
        odb::transaction trans(db.begin());

        db.update(stu);

        trans.commit();

    } catch (const std::exception& e) {
        LOG_ERROR("更新数据失败: {}", e.what());

        return false;
    }

    return true;
}

bool removeStudent(odb::mysql::database& db, Student& stu) {
    try {
        // 获取事务对象开启事务
        odb::transaction trans(db.begin());

        // db.erase_query<Student>(odb::query<Student>::name == "张三");
        db.erase<Student>(stu);

        trans.commit();

    } catch (const std::exception& e) {
        LOG_ERROR("删除数据失败: {}", e.what());

        return false;
    }

    return true;
}

bool classStudent(odb::mysql::database& db) {
    try {
        // 获取事务对象开启事务
        odb::transaction trans(db.begin());

        odb::result<ClassStudent> r(
            db.query<ClassStudent>(odb::query<ClassStudent>::classes::id == 2));
        for (auto it = r.begin(); it != r.end(); ++it) {
            std::cout << it->id_ << std::endl;
            std::cout << it->student_number_ << std::endl;
            std::cout << it->name_ << std::endl;
            std::cout << *(it->age_) << std::endl;
            std::cout << it->class_name_ << std::endl;
        }

        trans.commit();

    } catch (const std::exception& e) {
        LOG_ERROR("查询数据失败: {}", e.what());

        return false;
    }

    return true;
}

bool allName(odb::mysql::database& db) {
        try {
        // 获取事务对象开启事务
        odb::transaction trans(db.begin());

        odb::result<AllName> r(
            db.query<AllName>(odb::query<Student>::id == 2));
        for (auto it = r.begin(); it != r.end(); ++it) {
            std::cout << it->name_ << std::endl;
        }

        trans.commit();

    } catch (const std::exception& e) {
        LOG_ERROR("查询数据失败: {}", e.what());

        return false;
    }

    return true;
}

int main(int argc, char* argv[]) {
    google::ParseCommandLineFlags(&argc, &argv, true);        // 初始化全局参数
    initLogger(FLAGS_level, FLAGS_enable_debug, FLAGS_path);  // 初始化日志

    // 1. 构建连接池工厂配置对象
    std::unique_ptr<odb::mysql::connection_pool_factory> cpf =
        std::make_unique<odb::mysql::connection_pool_factory>(FLAGS_max_pool,
                                                              0);

    // 2. 构建数据库操作对象
    odb::mysql::database db(FLAGS_user, FLAGS_password, FLAGS_db, FLAGS_ip,
                            FLAGS_port, nullptr, FLAGS_charset, 0,
                            std::move(cpf));

    // 3. 操作数据库

    // insertClass(db);
    // insertStudent(db);
    // Student select_stu = selectStudent(db);
    // printf("select student number: %lu\n", select_stu.student_number());
    // printf("select student name: %s\n", select_stu.name().c_str());
    // if (select_stu.age()) {
    //     printf("select student age: %d\n", *(select_stu.age()));
    // }
    // printf("select student class id: %lu\n", select_stu.class_id());

    // select_stu.age(25);
    // updateStudent(db, select_stu);

    // removeStudent(db, select_stu);

    // classStudent(db);

    allName(db);

    return 0;
}